/*
	A class to deal with handling requests to and from the AMOS server.
*/

const AMOS_ROOT        = 'http://amosweb.cse.wustl.edu/';
const AMOS_DIR_LISTING = ( Site.DEBUG ) ? 'http://localhost:8080/amosDirListJpegs' : 'http://www.projectlive3d.com/amosDirListJpegs';

const NO_TIME_LAPSE_IMAGE = '/live3dstatic/images/notimelapseimage.png'

// the maximum image distance.  So if you click on a point in the
// image browser and the closest image is more than maxImageDist
// milleseconds away, it doesn't load that image.
const MAX_IMAGE_DISTANCE = 3600000; //(1 hour) 

// example: http://amosweb.cse.wustl.edu/static/results/90/0090/00000090/RGB2010.jpg

function AMOS(amosId, parent){
	this.amosId = amosId;
	var last_two_digits = amosId % 100;
	var last_four_digits = amosId % 10000;
	this.camera_path = pad(last_two_digits, 2) + '/' + pad(last_four_digits, 4) + '/' + pad(amosId, 8) + '/' 
	this.resultsDirectory = AMOS_ROOT + 'static/results/' + this.camera_path;
	this.baseDirectory = 'camera/' + amosId + '/';
	this.parent = parent;
	
	// initialize the time shown.
	var now = new Date();
	this.time = now;
	
	this.imageURLs = new Array();
	this.updateTimeLapseImage();
}

// sets the time from the interpolated position the user clicked
// on.
AMOS.prototype.getDateFromClick = function(x,y){
	var year = this.time.getUTCFullYear();
	var img = document.getElementById('ImageBrowser');
	
	var monthday = dayOfYearToMonthDay(x * img.width / 365, year);
	
	var floathours = -24.0 / img.height * y + 24;
	var hours = parseInt(floathours);
	var minutes = (floathours - hours) * 60;
	minutes = parseInt(minutes);
	
	this.time = new Date();
	this.time.setUTCFullYear(year);
	this.time.setUTCMonth(monthday.month - 1);
	this.time.setUTCDate(monthday.dayOfMonth);
	this.time.setUTCHours(hours);
	this.time.setUTCMinutes(minutes);
	this.time.setUTCSeconds(0);
}

AMOS.prototype.click = function(ev) {
	var pos = findPos(document.getElementById('ImageBrowser'));
	this.getDateFromClick(ev.clientX - pos.x, ev.clientY - pos.y);
	var me = this;
	this.loadImageURLs(function(){
						   me.imageSearch();
						   if (me.imageURL != null){
								me.parent.updateAMOSImage()
								me.parent.changeTexture()
								me.displayDate()

						   }
					   }, null);
	

}

// change the time lapse image.
AMOS.prototype.updateTimeLapseImage = function(){
	// add the false-color image.
	var year = this.time.getUTCFullYear();
	
	var imlocation = this.resultsDirectory + 'RGB' + year + '.jpg';
	var img = document.getElementById('ImageBrowser');
	img.setAttribute('src', imlocation)
	img.onerror = function(){
		img.setAttribute('src', NO_TIME_LAPSE_IMAGE)
	}
	document.getElementById('currYear').innerHTML = year;
}

// go to the previous year.
AMOS.prototype.prevYear = function(){
	// decrement the year.
	var yearAgo = this.time;
	yearAgo.setUTCFullYear(yearAgo.getUTCFullYear() - 1);
	
	// change the image.
	this.updateTimeLapseImage(yearAgo);
}

// go to the previous year.
AMOS.prototype.nextYear = function(){
	// decrement the year.
	var yearAgo = this.time;
	yearAgo.setUTCFullYear(yearAgo.getUTCFullYear() + 1);
	
	// change the image.
	this.updateTimeLapseImage(yearAgo);
}

// display the date underneath the image.
AMOS.prototype.displayDate = function(){
	var month  = this.time.getUTCMonth() + 1;
	var year   = this.time.getUTCFullYear();
	var day    = this.time.getUTCDate();
	var minute = this.time.getUTCMinutes();
	var hour   = this.time.getUTCHours();
	var second = this.time.getUTCSeconds();
	
	var datetime = document.getElementById('datetime');
	datetime.innerHTML = month + "/" + day + "/" + year + " at " + hour + ":" + pad(minute,2) + ":" + pad(second,2);
}

AMOS.prototype.loadImageURLs = function(onLoad, params){
	var month = this.time.getUTCMonth() + 1;
	var year = this.time.getUTCFullYear();
	month=pad(month, 2);
	year =pad(year, 4);
	if ((year + '-' + month) in this.imageURLs){
		// already cached.
		onLoad(params);
	} else{
		var http = createRequest();
		var url = AMOS_DIR_LISTING + '?camera_id=' + this.amosId + '&year=' + year + "&month=" + month;
		var me = this;
		http.open("GET", url, true);
		http.onreadystatechange = function(){
		    // Google Earth API has timeouts that happen if a query takes longer than 5 seconds.  If this happens, just try loading again...
		    if(http.status == 500){
		        me.loadImageURLs(onLoad, params);
		        return;
		    }
			if(http.readyState == 4){
				me.addImageURLS(month, year, http.responseXML);
				onLoad(params);
			}
		};
		http.send(null);
	}
}

// parses the results of an AJAX XML response.
AMOS.prototype.addImageURLS = function(month, year, response){
	if (response != null){
		//Get an array of all of the image tags
		var images = response.getElementsByTagName('image');
		
		//Read the image paths into an array
		var monthOfImages = new Array(images.length);
		for(var i = 0; i < images.length; i++){
			monthOfImages[i] = images[i].firstChild.nodeValue;	
		}
		
		//Add the array to the collection of loaded image URLs
		this.imageURLs[year + "-" + month] = monthOfImages;
	} else {
		this.imageURLs[year + "-" + month] = null;
	}
}

// find the closest image to the time given.
AMOS.prototype.searchForClosestImage =  function(){
	//Otherwise we know the month is loaded
	var year = this.time.getUTCFullYear();
	var month = this.time.getUTCMonth() + 1;
	month=pad(month, 2);
	this.currentMonth = this.imageURLs[year + "-" + month];
	if (this.currentMonth == null){
		return -1;
	}
	
	var closestImage = 0;
	var closestDistance = undefined;
	var closestDate = undefined;
	var dateTimeMilli = this.time.getTime();
	
	for(i = 0; i < this.currentMonth.length; i++){
		var currentDate = parseFileNameToDateTime(this.currentMonth[i]);
		var distance = Math.abs(currentDate.getTime() - dateTimeMilli);
		
		if(closestDistance == undefined || distance < closestDistance){
			closestImage = i;
			closestDistance = distance;
			closestDate = currentDate;
		}
	}
	
	//Ensure that the image we find is within a certain distance of the target
	if(closestDistance < MAX_IMAGE_DISTANCE){
		return closestImage;
	}
	return -1;
}

// returns the image closest to the value in "time", if one is located
// within an hour.
AMOS.prototype.imageSearch = function(){
	//Get the index of the 'closest' image to our target time
	var closestImage = this.searchForClosestImage();
	
	this.imageURL = null;
	//If an image was found, set that image as our main image
	if(closestImage >= 0){
	    // example: http://amosweb.cse.wustl.edu/image/90/20110707_082731.jpg
		this.imageURL = AMOS_ROOT + 'image/' + this.amosId + '/' + this.currentMonth[closestImage];
		this.time = parseFileNameToDateTime(this.currentMonth[closestImage])
	}
}


// is year a leap year?
function isLeapYear(year){
	if (year % 400 == 0)
		return true;
	else if (year % 100 == 0)
		return false;
	else if (year % 4 == 0)
		return true;
	else
		return false;
}

// Parses out the date that an image was captured, just given the file's name
function parseFileNameToDateTime(fileName){
	var year = fileName.substring(0,4);
	var month = fileName.substring(4,6);
	var day = fileName.substring(6,8);
	var hour = fileName.substring(9, 11);
	var minute = fileName.substring(11, 13);
	var second = fileName.substring(13,15);
	var toReturn = new Date();
	
	toReturn.setUTCFullYear(year);
	toReturn.setUTCMonth(month - 1);
	toReturn.setUTCDate(day);
	toReturn.setUTCHours(hour);
	toReturn.setUTCMinutes(minute);
	toReturn.setUTCSeconds(second);
	
	return toReturn;
}

// takes in a number from 1-366, and returns the (month,day) combination, where
// the day is the (day)th day of the year.
// Ex.  if day = 31, returns Jan 31.
//      if day = 32, returns Feb 1.
function dayOfYearToMonthDay(day, year){
	if (isLeapYear(year)){
		var daysInMonth = new Array(31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
	} else{
		var daysInMonth = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
	}
	month = 0;
	var daysLeft = day;
	while (daysLeft > daysInMonth[month]){
		daysLeft = daysLeft - daysInMonth[month];
		month++;
	}
	month = month + 1;
	
	return {dayOfMonth : daysLeft, month : month};
}
